// URL 编解码工具
class URLEncoder {
    /**
     * URL 编码
     * @param {string} input - 要编码的字符串
     * @param {Object} options - 编码选项
     * @returns {Object} - 处理结果
     */
    static encode(input, options = {}) {
        try {
            if (!input && input !== '') {
                return { success: false, error: '请输入要编码的内容' };
            }

            const {
                encodeType = 'uri-component',
                encodeSpaces = true,
                encodeSpecialChars = true
            } = options;

            let encoded;
            
            switch (encodeType) {
                case 'uri':
                    // encodeURI - 编码整个 URI，保留特殊字符如 :/?#[]@
                    encoded = encodeURI(input);
                    break;
                case 'uri-component':
                    // encodeURIComponent - 编码 URI 组件，编码所有特殊字符
                    encoded = encodeURIComponent(input);
                    break;
                case 'custom':
                    // 自定义编码
                    encoded = this.customEncode(input, encodeSpaces, encodeSpecialChars);
                    break;
                default:
                    encoded = encodeURIComponent(input);
            }

            return {
                success: true,
                data: {
                    original: input,
                    encoded: encoded,
                    type: encodeType,
                    originalLength: input.length,
                    encodedLength: encoded.length,
                    compressionRatio: ((encoded.length / input.length) * 100).toFixed(1) + '%'
                }
            };
        } catch (error) {
            return { success: false, error: 'URL编码失败: ' + error.message };
        }
    }

    /**
     * URL 解码
     * @param {string} input - 要解码的字符串
     * @param {Object} options - 解码选项
     * @returns {Object} - 处理结果
     */
    static decode(input, options = {}) {
        try {
            if (!input && input !== '') {
                return { success: false, error: '请输入要解码的内容' };
            }

            const { decodeType = 'uri-component' } = options;

            // 验证 URL 编码格式
            const validation = this.validateURLEncoded(input);
            if (!validation.isValid) {
                return { success: false, error: validation.error };
            }

            let decoded;
            
            try {
                switch (decodeType) {
                    case 'uri':
                        decoded = decodeURI(input);
                        break;
                    case 'uri-component':
                        decoded = decodeURIComponent(input);
                        break;
                    default:
                        decoded = decodeURIComponent(input);
                }
            } catch (decodeError) {
                // 如果标准解码失败，尝试自定义解码
                decoded = this.customDecode(input);
            }

            return {
                success: true,
                data: {
                    original: input,
                    decoded: decoded,
                    type: decodeType,
                    originalLength: input.length,
                    decodedLength: decoded.length,
                    compressionRatio: ((input.length / decoded.length) * 100).toFixed(1) + '%'
                }
            };
        } catch (error) {
            return { success: false, error: 'URL解码失败: ' + error.message };
        }
    }

    /**
     * 解析 URL 组件
     * @param {string} url - 要解析的 URL
     * @returns {Object} - 解析结果
     */
    static parseURL(url) {
        try {
            if (!url || !url.trim()) {
                return { success: false, error: '请输入URL' };
            }

            const cleanURL = url.trim();
            
            // 尝试解析URL
            let parsedURL;
            try {
                parsedURL = new URL(cleanURL);
            } catch (e) {
                // 如果没有协议，尝试添加 http://
                try {
                    parsedURL = new URL('http://' + cleanURL);
                } catch (e2) {
                    return { success: false, error: 'URL格式不正确' };
                }
            }

            // 解析查询参数
            const params = {};
            const searchParams = parsedURL.searchParams;
            for (const [key, value] of searchParams) {
                if (params[key]) {
                    // 处理重复参数
                    if (Array.isArray(params[key])) {
                        params[key].push(value);
                    } else {
                        params[key] = [params[key], value];
                    }
                } else {
                    params[key] = value;
                }
            }

            // 解析哈希片段
            const hashParts = parsedURL.hash ? this.parseHashFragment(parsedURL.hash) : {};

            return {
                success: true,
                data: {
                    original: cleanURL,
                    protocol: parsedURL.protocol,
                    hostname: parsedURL.hostname,
                    port: parsedURL.port || (parsedURL.protocol === 'https:' ? '443' : '80'),
                    pathname: parsedURL.pathname,
                    search: parsedURL.search,
                    hash: parsedURL.hash,
                    origin: parsedURL.origin,
                    host: parsedURL.host,
                    href: parsedURL.href,
                    params: params,
                    paramCount: Object.keys(params).length,
                    hashParts: hashParts,
                    components: {
                        scheme: parsedURL.protocol.replace(':', ''),
                        userInfo: parsedURL.username ? `${parsedURL.username}${parsedURL.password ? ':' + parsedURL.password : ''}` : '',
                        host: parsedURL.host,
                        path: parsedURL.pathname,
                        query: parsedURL.search.replace('?', ''),
                        fragment: parsedURL.hash.replace('#', '')
                    }
                }
            };
        } catch (error) {
            return { success: false, error: 'URL解析失败: ' + error.message };
        }
    }

    /**
     * 构建 URL
     * @param {Object} components - URL 组件
     * @returns {Object} - 构建结果
     */
    static buildURL(components) {
        try {
            const {
                protocol = 'https',
                hostname = '',
                port = '',
                pathname = '/',
                params = {},
                hash = ''
            } = components;

            if (!hostname) {
                return { success: false, error: '主机名不能为空' };
            }

            // 构建基础URL
            let url = `${protocol}://${hostname}`;
            
            // 添加端口
            if (port && port !== '80' && port !== '443') {
                url += `:${port}`;
            }
            
            // 添加路径
            if (pathname && pathname !== '/') {
                url += pathname.startsWith('/') ? pathname : '/' + pathname;
            }
            
            // 添加查询参数
            const paramEntries = Object.entries(params).filter(([key, value]) => key && value !== undefined);
            if (paramEntries.length > 0) {
                const searchParams = new URLSearchParams();
                paramEntries.forEach(([key, value]) => {
                    if (Array.isArray(value)) {
                        value.forEach(v => searchParams.append(key, v));
                    } else {
                        searchParams.set(key, value);
                    }
                });
                url += '?' + searchParams.toString();
            }
            
            // 添加哈希
            if (hash) {
                url += '#' + (hash.startsWith('#') ? hash.slice(1) : hash);
            }

            return {
                success: true,
                data: {
                    url: url,
                    components: components,
                    length: url.length
                }
            };
        } catch (error) {
            return { success: false, error: 'URL构建失败: ' + error.message };
        }
    }

    /**
     * 批量编解码
     * @param {string} input - 输入内容（每行一个）
     * @param {string} operation - 操作类型 ('encode' | 'decode')
     * @param {Object} options - 选项
     * @returns {Object} - 处理结果
     */
    static batchProcess(input, operation, options = {}) {
        try {
            if (!input || !input.trim()) {
                return { success: false, error: '请输入要处理的内容' };
            }

            const lines = input.split('\n').map(line => line.trim()).filter(line => line);
            
            if (lines.length === 0) {
                return { success: false, error: '没有有效的内容' };
            }

            const results = [];
            let successCount = 0;
            let errorCount = 0;

            for (let i = 0; i < lines.length; i++) {
                const line = lines[i];
                let result;
                
                if (operation === 'encode') {
                    result = this.encode(line, options);
                } else {
                    result = this.decode(line, options);
                }
                
                results.push({
                    line: i + 1,
                    input: line,
                    success: result.success,
                    output: result.success ? result.data.encoded || result.data.decoded : null,
                    error: result.success ? null : result.error
                });

                if (result.success) {
                    successCount++;
                } else {
                    errorCount++;
                }
            }

            return {
                success: true,
                data: {
                    operation: operation,
                    results: results,
                    summary: {
                        total: lines.length,
                        success: successCount,
                        error: errorCount
                    }
                }
            };
        } catch (error) {
            return { success: false, error: '批量处理失败: ' + error.message };
        }
    }

    /**
     * 自定义编码
     * @param {string} input - 输入字符串
     * @param {boolean} encodeSpaces - 是否编码空格
     * @param {boolean} encodeSpecialChars - 是否编码特殊字符
     * @returns {string} - 编码后的字符串
     */
    static customEncode(input, encodeSpaces = true, encodeSpecialChars = true) {
        let result = input;
        
        if (encodeSpaces) {
            result = result.replace(/ /g, '%20');
        }
        
        if (encodeSpecialChars) {
            // 编码常见的特殊字符
            const charMap = {
                '!': '%21', '"': '%22', '#': '%23', '$': '%24', '%': '%25',
                '&': '%26', "'": '%27', '(': '%28', ')': '%29', '*': '%2A',
                '+': '%2B', ',': '%2C', '/': '%2F', ':': '%3A', ';': '%3B',
                '<': '%3C', '=': '%3D', '>': '%3E', '?': '%3F', '@': '%40',
                '[': '%5B', '\\': '%5C', ']': '%5D', '^': '%5E', '`': '%60',
                '{': '%7B', '|': '%7C', '}': '%7D', '~': '%7E'
            };
            
            for (const [char, encoded] of Object.entries(charMap)) {
                result = result.replace(new RegExp('\\' + char, 'g'), encoded);
            }
        }
        
        return result;
    }

    /**
     * 自定义解码
     * @param {string} input - 输入字符串
     * @returns {string} - 解码后的字符串
     */
    static customDecode(input) {
        try {
            // 使用正则表达式匹配 %XX 格式
            return input.replace(/%([0-9A-Fa-f]{2})/g, (match, hex) => {
                return String.fromCharCode(parseInt(hex, 16));
            });
        } catch (error) {
            return input; // 如果解码失败，返回原始字符串
        }
    }

    /**
     * 验证 URL 编码格式
     * @param {string} input - 输入字符串
     * @returns {Object} - 验证结果
     */
    static validateURLEncoded(input) {
        try {
            // 检查是否包含无效的 % 编码
            const invalidPattern = /%(?![0-9A-Fa-f]{2})/;
            if (invalidPattern.test(input)) {
                return {
                    isValid: false,
                    error: '包含无效的URL编码格式（%后面必须跟两位十六进制数字）'
                };
            }

            // 检查是否包含不应该出现的字符
            const invalidChars = /[<>"{}|\\^`\s]/;
            const hasInvalidChars = invalidChars.test(input.replace(/%[0-9A-Fa-f]{2}/g, ''));
            
            if (hasInvalidChars) {
                return {
                    isValid: false,
                    error: '包含可能需要编码的特殊字符，请先编码或检查格式'
                };
            }

            return { isValid: true };
        } catch (error) {
            return {
                isValid: false,
                error: '格式验证失败: ' + error.message
            };
        }
    }

    /**
     * 解析哈希片段
     * @param {string} hash - 哈希字符串
     * @returns {Object} - 解析结果
     */
    static parseHashFragment(hash) {
        try {
            const cleanHash = hash.replace('#', '');
            const parts = {};
            
            // 尝试解析为查询参数格式
            if (cleanHash.includes('=')) {
                const pairs = cleanHash.split('&');
                for (const pair of pairs) {
                    const [key, value] = pair.split('=');
                    if (key) {
                        parts[decodeURIComponent(key)] = value ? decodeURIComponent(value) : '';
                    }
                }
            } else {
                // 作为简单片段处理
                parts.fragment = cleanHash;
            }
            
            return parts;
        } catch (error) {
            return { fragment: hash };
        }
    }

    /**
     * 获取 URL 编码字符映射表
     * @returns {Object} - 字符映射表
     */
    static getEncodingMap() {
        return {
            reserved: {
                '!': '%21', '#': '%23', '$': '%24', '&': '%26', "'": '%27',
                '(': '%28', ')': '%29', '*': '%2A', '+': '%2B', ',': '%2C',
                '/': '%2F', ':': '%3A', ';': '%3B', '=': '%3D', '?': '%3F',
                '@': '%40', '[': '%5B', ']': '%5D'
            },
            unreserved: {
                ' ': '%20', '"': '%22', '%': '%25', '<': '%3C', '>': '%3E',
                '\\': '%5C', '^': '%5E', '`': '%60', '{': '%7B', '|': '%7C',
                '}': '%7D', '~': '%7E'
            },
            extended: {
                '€': '%E2%82%AC', '‚': '%E2%80%9A', 'ƒ': '%C6%92', '„': '%E2%80%9E',
                '…': '%E2%80%A6', '†': '%E2%80%A0', '‡': '%E2%80%A1', 'ˆ': '%CB%86'
            }
        };
    }

    /**
     * URL 安全性检查
     * @param {string} url - 要检查的 URL
     * @returns {Object} - 检查结果
     */
    static securityCheck(url) {
        try {
            const issues = [];
            const warnings = [];
            
            // 检查协议
            if (url.toLowerCase().startsWith('javascript:')) {
                issues.push('包含JavaScript协议，可能存在XSS风险');
            }
            
            if (url.toLowerCase().startsWith('data:')) {
                warnings.push('包含Data URL，请确认数据来源可信');
            }
            
            // 检查可疑字符
            if (/<script|javascript:|vbscript:|on\w+=/i.test(url)) {
                issues.push('包含可疑的脚本代码');
            }
            
            // 检查多次编码
            const doubleEncoded = /%25[0-9A-Fa-f]{2}/;
            if (doubleEncoded.test(url)) {
                warnings.push('可能存在多次URL编码');
            }
            
            // 检查过长URL
            if (url.length > 2048) {
                warnings.push('URL长度超过2048字符，某些浏览器可能不支持');
            }
            
            return {
                success: true,
                data: {
                    url: url,
                    isSafe: issues.length === 0,
                    issues: issues,
                    warnings: warnings,
                    riskLevel: issues.length > 0 ? 'high' : warnings.length > 0 ? 'medium' : 'low'
                }
            };
        } catch (error) {
            return { success: false, error: '安全检查失败: ' + error.message };
        }
    }
}